package middlewares

import (
	"fmt"
	"net/http"

	"gitee.com/go-kade/go12/vblog/apps/token"
	"gitee.com/go-kade/go12/vblog/apps/user"
	"gitee.com/go-kade/go12/vblog/exception"
	"gitee.com/go-kade/go12/vblog/ioc"
	"gitee.com/go-kade/go12/vblog/response"
	"github.com/gin-gonic/gin"
)

// 用于鉴权的中间件
// 用于Token鉴权的中间件
type TokenAuth struct {
	tk   token.Service
	role user.Role
}

func NewTokenAuther() *TokenAuth {
	return &TokenAuth{
		tk: ioc.Controller().Get(token.AppName).(token.Service),
	}
}

// 怎么鉴权?
// Gin中间件 func(*Context)
func (a *TokenAuth) Auth(g *gin.Context) {
	// 1.获取token
	act, err := g.Cookie(token.TOKEN_COOKIE_NAME) //g.GetHeader("") 获取cookis中的access_token两种方式,登录时cookis携带了用户access_token，这里是拿到那个token做鉴权
	if err != nil {
		if err == http.ErrNoCookie {
			response.Failed(g, exception.NewAuthFound("cookie %s not found", token.TOKEN_COOKIE_NAME))
			return
		}
		response.Failed(g, err)
		return
	}
	// 2.调用token模块来认证
	in := token.NewValiateToken(act)
	tk, err := a.tk.ValiateToken(g.Request.Context(), in)
	if err != nil {
		response.Failed(g, err)
		return
	}
	fmt.Println(tk)
	// 把鉴权后的 结果: tk, 放到请求的上下文, 方便后面的业务逻辑使用
	if g.Keys == nil {
		g.Keys = map[string]any{}
	}
	g.Keys[token.TOKEN_GIN_KEY_NAME] = tk
}

// 权限鉴定, 鉴权是在用户已经认证的情况之下进行的
// 判断当前用户的角色
// 写带参数的 Gin中间件
func (a *TokenAuth) Perm(c *gin.Context) {
	// /Abort防止调用挂起的处理程序。
	//注意，这不会停止当前处理程序。假设您有一个授权中间件，用于验证当前请求是否已授权。如果授权失败(例如:密码不匹配)，调用Abort以确保不调用此请求的其余处理程序。
	// defer c.Abort()
	tkObj := c.Keys[token.TOKEN_GIN_KEY_NAME]
	if tkObj == nil {
		response.Failed(c, exception.NewAuthFound("token not found"))
		return
	}

	tk, ok := tkObj.(*token.Token)
	if !ok {
		response.Failed(c, exception.NewAuthFound("token not an *token.Token"))
		return
	}

	fmt.Printf("user %s role %d \n", tk.UserName, tk.Role)

	// 如果是Admin则直接放行
	if tk.Role == user.ROLE_ADMIN {
		return
	}

	if tk.Role == user.ROLE_AUTHOR {
		// response.Failed(c, exception.NewAuthFound("create role %d not allow", tk.Role))
		// c.Abort()
		return
	}

	if tk.Role != a.role {
		response.Failed(c, exception.NewAuthFound("role %d not allow", tk.Role))
		c.Abort()
		return
	}
}

// 写带参数的 Gin中间件1
func Required(r user.Role) gin.HandlerFunc {
	a := NewTokenAuther()
	a.role = r
	return a.Perm
}
